﻿
using System ;
using System.IO ;
using System.Data ;
using System.Drawing ;
using System.Windows.Forms ;
using System.Collections.Generic ;
using System.Threading ;
using System.Globalization ;

using MskEdit.Model ;
using MskEdit.Frontend ;
using MskEdit.Backend ;

using MskEdit.Msk.Model ;
using MskEdit.Msk.Backend ;
using MskEdit.Msk.Frontend ;
using MskEdit.Dxf.Model ;
using MskEdit.Dxf.Frontend ;
using MskEdit.Dbf.Backend ;


namespace MskEdit
{    
    internal sealed class Program
    {
        #region Private operations        

        private static DataTable getProjectsTable() { 

//            FileInfo dbfFileInfo = new FileInfo( @"C:\Users\Erik\Documents\SharpDevelop Projects\MskEdit\PROJECTS.DBF" ) ;
            // FileInfo dbfFileInfo = new FileInfo( @"..\..\..\..\MskEdit\PROJECTS.DBF" ) ;
            FileInfo dbfFileInfo = ProgramSettings.Default.projectsFileInfo ;

            string cwd = Directory.GetCurrentDirectory() ;
            DataTable projectsTable = DbfProjectsIO.tryGetProjectsTable( dbfFileInfo, null ) ;
            
            return projectsTable ;
        }


        private static void trySaveMskFile( ProgramComponents programComponents) {
        
            string outputPath = MskDocumentIO.TryGetOutputPath( null ) ;
            if ( outputPath == null )
                return ;
        
            MskDocument mskDocument = programComponents.AnyMskDocument ;
            if ( mskDocument == null )
                return ;

            MskDocumentIO.TryWrite( outputPath, mskDocument ) ;
        }
        
                
        private static DirectoryInfo tryGetProjectDirectoryInfo( ProgramSettings programSettings, string projectDirectoryName, DirectoryInfo fallbackValue ) {
        
            if ( programSettings.projectsContentDirectoryInfo.Exists == false )
                return fallbackValue ;
                
            string rootDirectoryName = programSettings.projectsContentDirectoryInfo.FullName ;
            DirectoryInfo projectDirectoryInfo = new DirectoryInfo( rootDirectoryName + projectDirectoryName ) ;
            
            if ( projectDirectoryInfo.Exists == false )
                return fallbackValue ;

            return projectDirectoryInfo ;
        }
        
        
        private static MskLine tryGetMskLine( ProgramComponents programComponents, MskLineKey anyMskLineKey, MskLine fallbackValue ) {       
            if ( anyMskLineKey == null )
                return fallbackValue ;
            else                
                return programComponents.tryGetMskLine( anyMskLineKey, fallbackValue ) ;
        }
        
        
        private static DxfAttrDataTable tryGetDxfAttrDataTable( ProgramComponents programComponents, string acadBlock, string acadTag, DxfAttrDataTable fallbackValue ) {
            DxfAttrDataTable dxfAttrDataTable = programComponents.tryGetDxfAttrDataTable( acadBlock, acadTag, fallbackValue ) ;
            return dxfAttrDataTable ;
        }

        #endregion

        #region Private event handlers

        private static void handleEditProgramSettingsRequest( ProgramSettingsForm ProgramSettingsForm, ProgramSettings ProgramSettings ) {
            ProgramSettingsForm.editProgramSettings( ProgramSettings ) ;
        }


        private static void handleProjectSelected( ProgramComponents programComponents, ProgramSettings programSettings, MskMainForm mskMainForm, string projectDirectoryName ) {
        
  //          DirectoryInfo projectDirectoryInfo = new DirectoryInfo( @"..\..\..\..\MskEdit\" + projectDirectoryName ) ;
  /*
            string rootDirectoryName = ProgramSettings.Default.projectsContentDirectoryInfo.FullName ;
            DirectoryInfo projectDirectoryInfo = new DirectoryInfo( rootDirectoryName + projectDirectoryName ) ;
*/
            DirectoryInfo projectDirectoryInfo = tryGetProjectDirectoryInfo( programSettings, projectDirectoryName, null ) ;

            Project anyProject = null ;           
            if ( projectDirectoryInfo != null )
                anyProject = ProjectIO.TryGetProject( projectDirectoryInfo, null ) ;
                
            programComponents.AnyProject = anyProject ;
            
            MskDocument anyMskDocument = null ;
            DxfDocument[] anyDxfDocuments = null ;
            if ( anyProject != null ) {
                anyMskDocument  = anyProject.AnyMskDocument ;
                anyDxfDocuments = anyProject.AnyDxfDocuments ;
            }

            mskMainForm.showAnyDxfDocuments( anyDxfDocuments ) ;
            mskMainForm.showAnyMskDocument( anyMskDocument, programSettings.showMskGridLines ) ; 
        }


        private static void handleSaveMskFileRequest( ProgramComponents programComponents ) {
            trySaveMskFile( programComponents ) ;
        }


        private static void handleApplicationExitRequest( MskMainForm mskMainForm ) {
            Application.Exit() ;
        }
        
        
        private static void handleMskLineContentChanged( ProgramComponents programComponents, MskLine mskLine ) {  
            var anyMskDocument = programComponents.AnyMskDocument ;
            if ( anyMskDocument != null )
                anyMskDocument.updateContentWith( mskLine ) ;
        }
        
        
        private static void handleShowMskGridLinesChanged( MskMainForm mskMainForm, bool showGridLines ) {
            mskMainForm.ShowsMskGridLines = showGridLines ;
        }

        #endregion

        #region Main program

        [STAThread]
        public static void Main( string[] args ) {
       
            Application.EnableVisualStyles() ;
            Application.SetCompatibleTextRenderingDefault( false ) ;
            
//            System.Diagnostics.Debug.Listeners.Add( new System.Diagnostics.DefaultTraceListener() ) ;

            
            // Files uses "." for decimal separator.
            // We want double.ToString() to follow same format.
            // Force InvariantCulture to handle that.
            Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture ;
            
//            MskEdit.Dxf.Tests.DxfTests.Run() ;

            // Construct application components.
            // We avoid using static global references to the components by 
            // coding all event handlers in lambda form with syntactic scoping.
            ProgramComponents   programComponents   = new ProgramComponents() ;
            MskMainForm         mskMainForm         = new MskMainForm() ;
            ProgramSettingsForm programSettingsForm = new ProgramSettingsForm() ;
            ProgramSettings     programSettings     = ProgramSettings.Default ;

            // Application
            mskMainForm.ApplicationExitRequested += () => 
                handleApplicationExitRequest( mskMainForm ) ;
                
            // Project
            mskMainForm.CalloutForProjectsTable = () => 
                getProjectsTable() ;
                
            mskMainForm.ProjectSelected += ( string projectDirectoryName ) => 
                handleProjectSelected( programComponents, programSettings, mskMainForm, projectDirectoryName ) ;

            // File  
            mskMainForm.SaveMskFileRequested += () => 
                handleSaveMskFileRequest( programComponents ) ;
                
            // Line
            mskMainForm.CalloutForMskLine = ( MskLineKey mskLineKey, MskLine fallbackValue ) =>
                tryGetMskLine( programComponents, mskLineKey, fallbackValue ) ;

            mskMainForm.CalloutForDxfAttrDataTable = ( string acadBlock, string acadTag, DxfAttrDataTable fallbackValue ) =>
                tryGetDxfAttrDataTable( programComponents, acadBlock, acadTag, fallbackValue ) ;
                
            mskMainForm.MskLineContentChanged += ( MskLine mskLine ) =>
                handleMskLineContentChanged( programComponents, mskLine ) ;
            
            // Program settings                
            mskMainForm.EditProgramSettingsRequested += () => 
                handleEditProgramSettingsRequest( programSettingsForm, ProgramSettings.Default ) ;

            ProgramSettings.Default.ShowMskGridLinesChanged += ( bool showGridLines ) => 
                handleShowMskGridLinesChanged( mskMainForm, showGridLines ) ;
            
            // Takeoff
            Application.Run( mskMainForm ) ;
        }
        
        #endregion      
    }
}
